﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Parameter;

namespace PSE.Deployment.SetupBase.Steps
{
    public class InstallProcessManagerInstance : SetupStep<Configuration.Actions.InstallProcessManagerInstance>
    {
        public InstallProcessManagerInstance(IStepGroup parent, Group group, Configuration.Actions.InstallProcessManagerInstance action, Parameter.Enums.SetupMode setupMode)
            : base(parent, group, action, setupMode)
        {
            this.ResetProgress();
        }

        public override void Execute()
        {
            this.ResetProgress();

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                InstallProcess();
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                UninstallProcess();
            }
        }

        public override void Undo()
        {
            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                UninstallProcess();
            }
        }

        private void InstallProcess()
        {
            foreach (ProcessManagerInstance instance in Action.Instances)
            {
                if (this.IsStopped())
                    return;

                instance.ProcessPath = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, instance.ProcessPath);

                if (instance.Processes.Count > 0)
                {
                    //Adiciona a instância
                    PSE.Deployment.Util.ProcessManager.GetInstance().AddInstance(instance.ProductName, instance.InstanceName, instance.InstanceAddress,
                        instance.ProcessPath, instance.STSAuthorityCertificateName, instance.ServiceCertificateName);

                    foreach (ProcessManagerProcess process in instance.Processes)
                    {
                        if (this.IsStopped())
                            return;

                        this.IncrementProgress(process.Description);

                        this.AddUsedBy(process.Description);

                        //Adiciona o processo da instância
                        PSE.Deployment.Util.ProcessManager.GetInstance().AddProcess(
                                          instance.ProductName,
                                          instance.InstanceName,
                                          process.Id,
                                          process.InteligenceModuleId,
                                          process.Name,
                                          process.Description,
                                          process.InstanceContext,
                                          process.Class,
                                          process.Assembly,
                                          process.FailureRecovery,
                                          process.InitializationType);
                    }                    
                }
            }
        }

        private void UninstallProcess()
        {
            List<InstalledArtefact> files = GetUsedFiles();

            for (int i = files.Count - 1; i >= 0; i--)
            {
                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall && this.IsStopped())
                    break;

                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
                    this.IncrementProgress(files[i].ArtefactName);
                else
                    this.DecrementProgress(files[i].ArtefactName);

                this.RemoveUsedBy(files[i].ArtefactName);

                System.Threading.Thread.Sleep(200);
            }

            foreach (ProcessManagerInstance instance in Action.Instances)
            {
                try
                {
                    PSE.Deployment.Util.ProcessManager.GetInstance().StopInstance(instance.ProductName, instance.InstanceName);
                }
                catch (Exception e1)
                {
                    SetupMainFactory.GetInstance().WriteStepLog(this, string.Format("Não foi possível parar a instância {0} do produto {1}", instance.InstanceName, instance.ProductName), e1);
                }
                finally
                {
                    try
                    {
                        PSE.Deployment.Util.ProcessManager.GetInstance().RemoveInstance(instance.ProductName, instance.InstanceName);
                    }
                    catch (Exception e2)
                    {
                        SetupMainFactory.GetInstance().WriteStepLog(this, string.Format("Não foi possível remover a instância {0} do produto {1}", instance.InstanceName, instance.ProductName), e2);
                    }
                }
            }
        }

        private void ResetProgress()
        {
            this.ResetProgress(Action.Instances.Sum(p => p.Processes.Count));
        }
    }
}
